import pymysql
import logging
from typing import Optional, Dict, Any, List
from contextlib import contextmanager

logger = logging.getLogger(__name__)

class DatabaseConfig:
    """数据库配置类"""
    
    # 数据库连接配置
    HOST = 'localhost'
    PORT = 3306
    USER = 'root'
    PASSWORD = '123456'
    DATABASE = 'fastapi'
    CHARSET = 'utf8mb4'
    COLLATION = 'utf8mb4_unicode_ci'
    AUTocommit = True
    
    # 连接池配置
    MAX_CONNECTIONS = 10
    CONNECTION_TIMEOUT = 30
    
    @classmethod
    def get_connection_params(cls) -> Dict[str, Any]:
        """获取数据库连接参数"""
        return {
            'host': cls.HOST,
            'port': cls.PORT,
            'user': cls.USER,
            'password': cls.PASSWORD,
            'database': cls.DATABASE,
            'charset': cls.CHARSET,
            'autocommit': cls.AUTocommit
        }
    
    @classmethod
    def create_connection(cls):
        """创建数据库连接"""
        try:
            connection = pymysql.connect(**cls.get_connection_params())
            return connection
        except Exception as e:
            logger.error(f"数据库连接失败: {str(e)}")
            raise
    
    @classmethod
    @contextmanager
    def get_connection(cls):
        """获取数据库连接的上下文管理器"""
        connection = None
        try:
            connection = cls.create_connection()
            yield connection
        except Exception as e:
            logger.error(f"数据库连接失败: {str(e)}")
            raise
        finally:
            if connection:
                connection.close()
    
    @classmethod
    def test_connection(cls):
        """测试数据库连接"""
        try:
            connection = pymysql.connect(
                host=cls.HOST,
                port=cls.PORT,
                user=cls.USER,
                password=cls.PASSWORD,
                database=cls.DATABASE,
                charset=cls.CHARSET,
                autocommit=cls.AUTocommit
            )
            cursor = connection.cursor()
            cursor.execute("SELECT 1")
            result = cursor.fetchone()
            cursor.close()
            connection.close()
            logger.info("数据库连接测试成功")
            return True
        except Exception as e:
            logger.error(f"数据库连接测试失败: {str(e)}")
            return False

class DatabaseManager:
    """数据库管理器"""
    
    _connection = None
    
    @classmethod
    def get_connection(cls):
        """获取数据库连接（单例模式）"""
        if cls._connection is None or not cls._connection.open:
            cls._connection = DatabaseConfig.create_connection()
        return cls._connection
    
    @classmethod
    def close_connection(cls):
        """关闭数据库连接"""
        if cls._connection and cls._connection.open:
            cls._connection.close()
            cls._connection = None
    
    @classmethod
    @contextmanager
    def get_cursor(cls, cursor_type=pymysql.cursors.DictCursor):
        """获取数据库游标的上下文管理器"""
        connection = cls.get_connection()
        cursor = connection.cursor(cursor_type)
        try:
            yield cursor
        finally:
            cursor.close()
    
    @classmethod
    def execute_query(cls, query: str, params: Optional[tuple] = None, cursor_type=pymysql.cursors.DictCursor):
        """执行查询并返回结果"""
        try:
            with cls.get_cursor(cursor_type) as cursor:
                cursor.execute(query, params)
                result = cursor.fetchall()
                return result if result else []
        except Exception as e:
            logger.error(f"查询执行失败: {e}")
            logger.error(f"查询语句: {query}")
            logger.error(f"参数: {params}")
            raise
    
    @classmethod
    def execute_update(cls, query: str, params: Optional[tuple] = None):
        """执行更新操作"""
        try:
            with cls.get_cursor() as cursor:
                affected_rows = cursor.execute(query, params)
                return affected_rows
        except Exception as e:
            logger.error(f"更新执行失败: {e}")
            logger.error(f"更新语句: {query}")
            logger.error(f"参数: {params}")
            raise
    
    @classmethod
    def execute_insert(cls, query: str, params: Optional[tuple] = None):
        """执行插入操作"""
        try:
            with cls.get_cursor() as cursor:
                cursor.execute(query, params)
                return cursor.lastrowid
        except Exception as e:
            logger.error(f"插入执行失败: {e}")
            logger.error(f"插入语句: {query}")
            logger.error(f"参数: {params}")
            raise

# 便捷函数
def get_db_connection():
    """获取数据库连接"""
    return DatabaseManager.get_connection()

def execute_query(query: str, params: Optional[tuple] = None):
    """执行查询"""
    return DatabaseManager.execute_query(query, params)

def execute_update(query: str, params: Optional[tuple] = None):
    """执行更新"""
    return DatabaseManager.execute_update(query, params)

def execute_insert(query: str, params: Optional[tuple] = None):
    """执行插入"""
    return DatabaseManager.execute_insert(query, params) 